/**
 * 
 */
package com.ws.framework.remoteservice.core.provider;

import java.lang.reflect.Method;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.google.common.collect.Maps;
import com.ws.framework.remoteservice.core.ex.WRSIException;
import com.ws.framework.remoteservice.core.model.Invocation;
import com.ws.framework.remoteservice.core.model.Result;
import com.ws.framework.remoteservice.core.model.ServiceKey;

/**
 * @author WSH
 *
 */
public class ServiceExecutorImpl implements ServiceExecutor {

	private final Logger logger = Logger.getLogger(this.getClass().getName());

	private static final ConcurrentMap<ServiceKey, Object> registered = Maps.newConcurrentMap();

	public static final ServiceExecutorImpl instance = new ServiceExecutorImpl();

	private ServiceExecutorImpl() {
	}

	@Override
	public Set<ServiceKey> getRegisteredServiceKeys() {
		return registered.keySet();
	}

	@Override
	public void register(ServiceKey key, Object serviceImpl) {
		registered.putIfAbsent(key, serviceImpl);
	}

	@Override
	public Result invoker(Invocation invocation) throws Exception {
		logger.log(Level.INFO, "Invoker start... id: " + invocation.getId());
		Object target = registered.get(invocation.getServiceKey());
		if (null == target) {
			String exMsg = "No contract class had bean registerd support handler for this key "
					+ invocation.getServiceKey();
			logger.warning(exMsg);
			Result result = new Result(invocation.getId(), null);
			result.setSuccess(false);
			result.setThrowable(new WRSIException(exMsg));
			return result;
		}
		Object[] arguments = invocation.getArguments();
		if (null == arguments)
			arguments = new Object[] {};
		try {
			Method method = target.getClass().getMethod(invocation.getMethod(), invocation.getParameterTypes());
			Result result = new Result(invocation.getId(), method.invoke(target, arguments));
			result.setSuccess(true);
			return result;
		} catch (Exception e) {
			logger.log(Level.WARNING, "Invocation " + invocation.getId() + " occur Exception", e);
			Result result = new Result(invocation.getId(), null);
			result.setSuccess(false);
			result.setThrowable(e);
			return result;
		} finally {
			logger.log(Level.INFO, "Invoker end... id: " + invocation.getId());
		}
	}
}
